/** \file
* Declarations for the portable Thread class.
* This file is part of Chorus, available at
* http://code.google.com/p/chorus-twitter/ . This file and all associated files
* and derivative works are bound by the terms of the LGPL 3.0 license,
* available at http://www.gnu.org/licenses/lgpl-3.0-standalone.html .
* \par Subversion URL:
* \$URL: http://chorus-twitter.googlecode.com/svn/branches/cpp/src/system/Thread.hpp $
* \version \$Rev: 152 $
* \date    \$Date: 2010-04-06 07:35:13 +0000 (Tue, 06 Apr 2010) $
*/

#pragma once

#include <list>

#ifdef WIN32
#	include <windows.h>
#endif

#ifdef POSIX
#	include <pthread.h>
#	include "system/Mutex.hpp"
#endif

#include "system/ThreadCall.hpp"
#include "system/DebugConsole.hpp"

/// The thread support class. For portability, compile Thread-posix.cpp or
/// Thread-win32.cpp depending on which system you need.
class Thread
{
public:
	/// The constructor. It's templated so that the callee class type can be
	/// considered. CalleeType is the class type of the callee.
	/// \param calleeInit A reference to the callee instance.
	/// \param funcInit   A pointer to the callee member function.
	template <typename CalleeType>
	Thread(CalleeType &calleeInit, bool(CalleeType::*funcInit)())
	{
		call = new TypedThreadCall<CalleeType>(calleeInit, funcInit);
		if (!call)
		{
			PDEBUG("new failed");
			return;
		}
		allthreads.push_back(this);
		init();
	}

	/// The destructor.
	~Thread();

public:
	/// Start the thread.
	/// \return True for success.
	bool start();

	/// Pause the thread.
	/// \return True for success.
	bool pause();

	/// Resume the thread.
	/// \return True for success.
	bool resume();

	/// Abort the thread.
	/// \return True for success.
	bool abort();

	/// Wait for the thread to finish.
	bool wait();

	/// Wait for the specified period, and then abort the thread if it hasn't
	/// already finished.
	/// \param timeoutms The timeout period, in milliseconds.
	/// \return True for success.
	bool waitThenAbort(unsigned timeoutms);

#ifdef POSIX
	/// Wait for the specified period, and then abort the thread if it hasn't
	/// already finished.
	/// \param timeoutts The timeout period, as a timespec.
	/// \return True for success.
	bool waitThenAbort(timespec timeoutts);
#endif

	/// Check if the thread has completed.
	/// \return True if the thread has completed.
	bool isDone();

	/// Wait for the specified period on the list of threads provided, and then
	/// abort the threads that haven't already finished.
	/// \param threads   The threads to wait on.
	/// \param timeoutms The timeout period, in milliseconds.
	/// \return True for success.
	static bool waitThenAbort(std::list<Thread*> &threads, unsigned timeoutms);

	/// Wait for the specified period on all current thread instances, and
	/// abort the threads that haven't already finished.
	/// \param timeoutms The timeout period, in milliseconds.
	/// \return True for success.
	static bool waitAllThenAbort(unsigned timeoutms)
	{
		return waitThenAbort(allthreads, timeoutms);
	}

	/// Get the ID of the caller thread.
	/// \return The thread ID.
	static unsigned getCurrentThreadID();

	/// Call the callee function.
	/// \return True for success.
	bool callFunc();

private:
	/// Initialize the thread object.
	/// \return True for success.
	bool init();

	/// Uninitialize the thread object.
	/// \return True for success.
	bool uninit();

#ifdef WIN32
	/// Free the thread handle.
	/// \return True for success.
	bool freeHandle();

	/// The static thread callback function.
	/// \param param The this-pointer.
	/// \return The win32 thread error value.
	static unsigned long WINAPI callback(void *param);
#endif

#ifdef POSIX
	/// The static thread callback function.
	/// \param param The this-pointer.
	/// \return The posix thread error value.
	static void *callback(void *param);
#endif

private:
	/// The thread call instance, containing a pointer to the callee instance
	/// and its function.
	ThreadCall *call;

#ifdef WIN32
	/// The win32 thread handle.
	HANDLE hthread;
	/// The win32 thread ID.
	unsigned long threadid;
#endif

#ifdef POSIX
	/// The posix thread attribute object.
	pthread_attr_t threadattr;
	/// The posix thread.
	pthread_t thread;
	/// The posix thread mutex.
	Mutex mutex;
	/// The pthread condition variable object.
	pthread_cond_t cond;
#endif

	/// The list of all Thread instances.
	static std::list<Thread*> allthreads;
};
